/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package traffic.light.simulator.town.cars;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import traffic.light.simulator.town.unity.RoadElement;
import traffic.light.simulator.town.Town;
import traffic.light.simulator.town.trafficLight.TrafficLight;
import traffic.light.simulator.util.*;

/**
 * Class representing a car
 *
 */
public class Car implements IDrawable {

    public static int SIZE;
    
    protected Position pos;
    protected Town town;
    protected Color clr;
    protected RoadElement currentRoad;
    protected int directionX;
    protected int directionY;

    /**
     * Constructor of the Car
     * @param clr : the color of the car
     * @param town : the town where the car is stored
     */
    public Car(Color clr, Town town) {
        this.clr = clr;
        this.town = town;
        this.pos = new Position();
    }

    private void goRight() {
        directionX = 1;
        directionY = 0;
    }

    private void goLeft() {
        directionX = -1;
        directionY = 0;
    }

    private void goDown() {
        directionX = 0;
        directionY = 1;
    }

    private void goUp() {
        directionX = 0;
        directionY = -1;
    }

    public void setPosition(Position p) {
        this.pos = p;
        currentRoad = town.getRoadElementAt(pos);
        currentRoad.setFree(false);
    }

    public Position getPosition() {
        return pos;
    }

    @Override
    public void draw(Graphics g) {
        g.setColor(clr);
        g.fillRect(pos.getX(), pos.getY(), SIZE, SIZE);
    }

    /**
     * @return Position : the center Position of the car
     */
    protected Position centerOfCar() {
        return new Position(pos.getX() + SIZE / 2, pos.getY() + SIZE / 2);
    }

    /**
     * @return Position : the next position of the car
     */
    protected Position nextCarPosition() {
        Position p = centerOfCar();
        switch (directionX) {
            case -1:
                p.setX(p.getX() - SIZE / 2);
                break;
            case 1:
                p.setX(p.getX() + SIZE / 2);
                break;
        }
        switch (directionY) {
            case -1:
                p.setY(p.getY() - SIZE / 2);
                break;
            case 1:
                p.setY(p.getY() + SIZE / 2);
                break;
        }
        return p;
    }

    /*
     * Update the car considering some rules of traffic
     */
    public void update() {
        RoadElement road = town.getRoadElementAt(centerOfCar());
        if (road != null) {
            RoadElement r2 = town.getRoadElementAt(new Position(pos.getX() + SIZE - 2, pos.getY()));
            RoadElement r3 = town.getRoadElementAt(new Position(pos.getX(), pos.getY() + SIZE - 2));
            RoadElement r4 = town.getRoadElementAt(new Position(pos.getX() + SIZE - 2, pos.getY() + SIZE - 2));
            boolean greenTrafficLight = true;
            TrafficLight tl = road.getTL();

            if (tl != null) {
                greenTrafficLight = tl.getTLValueFromPosition(road.getAbsX(), road.getAbsY());
            }

            if (road == r2
                    && r2 == r3
                    && r3 == r4) {
                updateDirection();
            }

            if (greenTrafficLight) {
                RoadElement nextRoad = town.getRoadElementAt(nextCarPosition());
                if (road == currentRoad) {
                    move();
                } else if (nextRoad.isFree()) {
                    currentRoad.setFree(true);
                    currentRoad = road;
                    currentRoad.setFree(false);
                    move();
                }
            }
        }
    }

    protected void updateDirection() {
        if (currentRoad.canGoDown() && currentRoad.canGoLeft()) {
            if (new Random().nextBoolean()) {
                goDown();
            } else {
                if (new Random().nextBoolean()) {
                    goLeft();
                }
            }
        } else if (currentRoad.canGoDown() && currentRoad.canGoRight()) {
            if (new Random().nextBoolean()) {
                goDown();
            } else {
                if (new Random().nextBoolean()) {
                    goRight();
                }
            }
        } else if (currentRoad.canGoUp() && currentRoad.canGoRight()) {
            if (new Random().nextBoolean()) {
                goUp();
            } else {
                if (new Random().nextBoolean()) {
                    goRight();
                }
            }
        } else if (currentRoad.canGoUp() && currentRoad.canGoLeft()) {
            if (new Random().nextBoolean()) {
                goUp();
            } else {
                if (new Random().nextBoolean()) {
                    goLeft();
                }
            }
        } else if (currentRoad.canGoLeft()) {
            goLeft();
        } else if (currentRoad.canGoRight()) {
            goRight();
        } else if (currentRoad.canGoUp()) {
            goUp();
        } else if (currentRoad.canGoDown()) {
            goDown();
        }
    }

    protected void move() {
        pos.setX(pos.getX() + directionX);
        pos.setY(pos.getY() + directionY);
        if (pos.getX() < 0
                || pos.getY() < 0
                || nextCarPosition().getX() >= town.getSize().width
                || nextCarPosition().getY() >= town.getSize().height) {
            currentRoad.setFree(true);
            town.outOfBounds(this);
        }
    }

    @Override
    public String toString() {
        String dirX = "none";
        String dirY = "none";
        switch (directionX) {
            case -1:
                dirX = "left";
                break;
            case 1:
                dirX = "right";
                break;
        }

        switch (directionY) {
            case -1:
                dirX = "left";
                break;
            case 1:
                dirX = "right";
                break;
        }
        return "Car : \n"
                + "\tSize : " + Car.SIZE + "\n"
                + "\tdirection on X : " + dirX + "\n"
                + "\tdirection on Y : " + dirY + "\n";
    }

    @Override
    public void draw(Graphics g, boolean editionMode) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
